#include <iostream>
#include <string>

using namespace std;

#define	BOARD_COLUMNS	7
#define BOARD_ROWS		6
#define CONNECT_NUM		4

//#define DRAW_NUMBERS	// true

// console colour escape codes
char red[] = { 0x1b, '[', '3', '1', ';', '4', '1', 'm', 0 };	// following text red
char yellow[] = { 0x1b, '[', '3', '3', ';', '4', '3', 'm', 0 };	// following text yellow
char normal[] = { 0x1b, '[', '0', ';', '3', '9', 'm', 0 };		// black bg, white text

// column, row coorinates struct
typedef struct s_position
{
	int col;
	int row;
};

class gameBoard
{
	private:
		int array[BOARD_COLUMNS][BOARD_ROWS];	// columns, rows
		
		int playerOneColour;
		int playerTwoColour;
		
		int total_turns;	// keep track of the number of turns this game has had
		
		int player_turn;	// which players turn is it (1 or 2)
		
		s_position last_move;	// 'coordinates' of last move
		
	public:
		gameBoard();
		// constructor
		
		~gameBoard();
		// destructor
		
		void setPlayerColour(int player, int colour);
		// sets 
	
		bool dropPieceInColumn(int player, int col);
		// drops a piece in column col. returns false if column is full
		
		int checkConnect4();
		// checks if a connect 4 has occured
		// returns the number of the player that has won
		// or (-1, no win) or (-2, cats game)
		
		int getPlayerTurn();
		// returns which players turn it is
	
		int getTotalTurns();
		// returns total turns in this game
		
		void draw();
		// draws the game board
		
		void clear();
		// clears the game board (removes all pieces)
};

// constructor
gameBoard::gameBoard()
{
	// clear game board
	this->clear();
	// set default player 'colours'
	this->setPlayerColour(1, 1);
	this->setPlayerColour(2, 2);
	// init
	player_turn = 1;	// randomize?
	total_turns = 0;
	last_move.col = -1;
	last_move.row = -1;
}

// destructor
gameBoard::~gameBoard()
{
	// empty
}

// sets the player piece colour
void gameBoard::setPlayerColour(int player, int colour)
{
	if (player == 1)
		playerOneColour = colour;
	else
		playerTwoColour = colour;
}

// drops a piece in column col. returns false if column is full
bool gameBoard::dropPieceInColumn(int player, int col)
{
	// look for the next open spot in the column
	for (int i=0; i<BOARD_ROWS; i++)
	{
		if (array[col][i] == 0)
		{
			array[col][i] = (player == 1) ? playerOneColour : playerTwoColour;	// drop piece
			total_turns++;	// increment total turns
			player_turn = (player_turn == 1) ? 2 : 1;	// toggle player turn
			last_move.col = col;
			last_move.row = i;
			return true;
		}
	}
	return false;
}

// checks if a connect 4 has occured
// returns the number of the player that has won
// or (-1, no win) or (-2, cats game)
int gameBoard::checkConnect4()
{
	if (last_move.col == -1 || last_move.row == -1)
		return -1;
	
	s_position tmp;
	int curr_colour;
	int in_a_row;
	
	/// look for 4 in a row four directions: up/down, left/right, diagonal1, diag2
	
	// diagonal up left
	for(tmp.col=last_move.col, tmp.row=last_move.row; 	// start from bottom right
		tmp.col < BOARD_COLUMNS && tmp.row > 0;
		tmp.col++, tmp.row--);
		
	for(curr_colour=array[tmp.col][tmp.row], in_a_row=0;
		tmp.col > 0 && tmp.row < BOARD_ROWS;			// check for 4 in a row, up to left
		tmp.col--, tmp.row++)
	{
		if (array[tmp.col][tmp.row] == curr_colour && curr_colour != 0)
		{
			if (++in_a_row == CONNECT_NUM)	return (curr_colour == playerOneColour) ? 1 : 2;
		}
		else 
		{
			curr_colour = array[tmp.col][tmp.row];
			in_a_row = 1;
		}
	}
	
	// diagonal up right
	for(tmp.col=last_move.col, tmp.row=last_move.row; 	// start from bottom left
		tmp.col > 0 && tmp.row > 0;
		tmp.col--, tmp.row--);
		
	for(curr_colour=array[tmp.col][tmp.row], in_a_row=0;
		tmp.col < BOARD_COLUMNS && tmp.row < BOARD_ROWS;			// check for 4 in a row, up to right
		tmp.col++, tmp.row++)
	{
		if (array[tmp.col][tmp.row] == curr_colour && curr_colour != 0)
		{
			if (++in_a_row == CONNECT_NUM)	return (curr_colour == playerOneColour) ? 1 : 2;
		}
		else 
		{
			curr_colour = array[tmp.col][tmp.row];
			in_a_row = 1;
		}
	}
	
	// up/down
	tmp.col = last_move.col;
	tmp.row = 0; 	// start from bottom

	for(curr_colour=array[tmp.col][tmp.row], in_a_row=0;
		tmp.row < BOARD_ROWS;			// check for 4 in a row, up
		tmp.row++)
	{
		if (array[tmp.col][tmp.row] == curr_colour && curr_colour != 0)
		{
			if (++in_a_row == CONNECT_NUM)	return (curr_colour == playerOneColour) ? 1 : 2;
		}
		else 
		{
			curr_colour = array[tmp.col][tmp.row];
			in_a_row = 1;
		}
	}
	
	// left/right
	tmp.col = 0;
	tmp.row = last_move.row; 	// start from left

	for(curr_colour=array[tmp.col][tmp.row], in_a_row=0;
		tmp.col < BOARD_COLUMNS;			// check for 4 in a row, up
		tmp.col++)
	{
		if (array[tmp.col][tmp.row] == curr_colour && curr_colour != 0)
		{
			if (++in_a_row == CONNECT_NUM)	return (curr_colour == playerOneColour) ? 1 : 2;
		}
		else 
		{
			curr_colour = array[tmp.col][tmp.row];
			in_a_row = 1;
		}
	}
	
	// check for cats game
	for (tmp.row = BOARD_ROWS-1, tmp.col = 0;
		tmp.col < BOARD_COLUMNS;
		tmp.col++)
	{
		if (array[tmp.col][tmp.row] == 0)
			break;
		else if(tmp.col == BOARD_COLUMNS-1)
			return -2;	// cats!
	}
	
	// no win yet
	return -1;
}

// returns which players turn it is
int gameBoard::getPlayerTurn()
{
	return player_turn;
}

// returns total turns in this game
int gameBoard::getTotalTurns()
{
	return total_turns;
}

// draws the game board
void gameBoard::draw()
{
	cout << "\n";
	for (int j=BOARD_ROWS-1; j >= 0; j--)
	{
		cout << "  -----------------------------\n";
		#ifdef DRAW_NUMBERS
			cout << j+1;
		#else
			cout << " ";
		#endif
		for (int i=0; i < BOARD_COLUMNS; i++)
		{
			cout << " | ";
				if (array[i][j] == 1)	cout << red; else if (array[i][j] == 2)	cout << yellow;
			cout << " "; //cout << array[i][j];
				cout << normal;
		}
		cout << " |\n";
	}
	cout << "  -----------------------------\n";
	cout << "    1   2   3   4   5   6   7\n";
}

// clears the game board (removes all pieces)
void gameBoard::clear()
{
	// clear game board
	for (int i=0; i<BOARD_COLUMNS; i++)
	{
		for (int j=0; j<BOARD_ROWS; j++)
		{
			array[i][j] = 0;
		}
	}
}

void _clearScreen()
{
	cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
}

int main()
{
	char input[100];
	int num;
	gameBoard connect4;
	
	while(connect4.checkConnect4() == -1)
	{
		_clearScreen();
		cout << "       ---- CONNECT 4 ----        (type quit to exit)";
		connect4.draw();
		cout << "\nTurn: Player ";
			if (connect4.getPlayerTurn() == 1)	cout << red; else if (connect4.getPlayerTurn() == 2)	cout << yellow;
		cout << connect4.getPlayerTurn();
			cout << normal;
		cout << "\nPlace piece in which column (1-7)? ";
		cin >> input;
		
		if ( strncmp(input, "quit",4)==0 )
			return 0;
		num = atoi(input);
		if (num < 8 && num > 0)
			connect4.dropPieceInColumn(connect4.getPlayerTurn(), num-1);
	}
	
	_clearScreen();
	connect4.draw();
	if (connect4.checkConnect4() == -2)
	{
		cout << "\nCats Game!";
	}
	else
	{
		cout << "\nPlayer ";
			if (connect4.checkConnect4() == 1)	cout << red; else if (connect4.checkConnect4() == 2)	cout << yellow;
		cout << connect4.checkConnect4();
			cout << normal;
		cout << " wins!";
	}
	
	cout << endl;

	return 0;
}
